//@+leo-ver=5-thin
//@+node:sonam.20180318222344.1: * @file PlanetCycle.pas
//@+at
// 該單元主要用來按照六種不同的歷算論典計算各曜的三日共年之週年
// 
//@@c
unit PlanetCycle;

//@+others
//@+node:sonam.20180324202608.1: ** Interface
//@@c
interface

uses SysUtils;
//@+node:sonam.20180324203157.1: *3* 常量
//@@c
Const
//@+node:sonam.20180318214150.1: *4* 紀年
//@+at 本程序中的紀年均採用勝生紀年，該紀年是以《時輪經》傳譯到西藏的時間西元1027年
// 作為勝生元年，因此耶穌誕生的時間是在勝生前1026年，《總滙如意寶》所使用的歷元
// 丁卯年西元1987年是勝生961年。
// 
//@@c
	ChristianBeginYear = -1026;
	ManiBeginYear = 961;
	TibetCalendarBeginYear = 0;
//@+node:sonam.20180324214953.1: *3* 類型聲明
//@@c
Type
//@+node:sonam.20180318213641.2: *4* 歷算論典
//@+at 按照《總滙如意寶》中給出的歷算方法，一共有六種常用的歷算論典，分別是《白蓮口授》、
// 《智者心要如意寶》、《甘丹新算》、《再明炬》、《脩訂再明炬》和《順作用派》。
// 
//@@c
	CalcBook = (WhiteLotus=1, WizardHeart, GanDanNew,
				BrighterLight, ChangedBrighter, LightEffectCommon);
//@+node:sonam.20180318214056.1: *4* 曜
//@+at 這裏的曜有輪值曜、日、整零、羅睺、火曜、木曜、土曜、水曜、金曜共有九種。
// 
//@@c
	Planet = (Week=1, Sun, Moon, sGragCan, Mars, Jupiter, Saturn, Mercury, Venus);
//@+node:sonam.20180324215805.1: *4* 有關曜的表
//@@c
	TPlanetTab = array [1..9] of Int64;
	TPlanetTabs = array [1..6] of TPlanetTab;
//@+node:sonam.20180324215850.1: *4* TPlanetCycle類
//@+at
// 該類提供了取得三日共年之週年、太隂月週期、宮日週期、太陽日週期等的方法
// 
//@@c
	TPlanetCycle = class(TObject)
	public
		function YearInCycle(book: CalcBook; p: Planet; y: Integer) : Integer;
        function GetDividend(p: Planet; accMoon: Int64): Int64;
        function MonthCycle(p: Planet) : Int64;
        function ZodiacDayCycle(p: Planet) : Int64;
        function DayCycle(p: Planet) : Int64;
	end;

// 計算y年中經過的積月數
function PlanetAccumMonth(y, month : Integer; LeapMonth: Boolean) : Int64;
//@+node:sonam.20180324220126.1: ** Implementation
//@@c
Implementation
//@+node:sonam.20180324220307.1: *3* 常量
//@@c
Const
//@+node:sonam.20180318214337.1: *4* 表二－太隂月週期及週期數
//@@c
	MonthCycleTab : TPlanetTab =
	  (39592, 804, 3528, 230, 1295224, 8167264, 60892496, 12438958, 2118172);
	MonthCycleNum : TPlanetTab =
      (8657, 65, 253, 1, 55675, 55675, 167025, 4175625, 278375);
//@+node:sonam.20180318214413.1: *4* 表四－宮日週期及週期數
//@@c
	ZodiacDayCycleTab : TPlanetTab =
	  (344846320, 360, 6879600, 448500, 101027472, 637046592, 1583204896, 1293651632, 330434832);
	ZodiacDayCycleNum : TPlanetTab =
      (49985015, 1, 253327, 67, 149209, 149209, 149209, 14920900, 1492090);

//@+node:sonam.20180318214429.1: *4* 表五－太陽日週期及週期數
//@@c
	DayCycleTab : TPlanetTab =
	  (7,6714405,589264200,76831500,687,4332,10766,8797,2247);
	DayCycleNum : TPlanetTab =
      (1,18382,21385336,11312,1,1,1,100,10);
//@+node:sonam.20180324220946.1: *3* MonthCycle
//@@c
function TPlanetCycle.MonthCycle(p: Planet) : Int64;
begin
    result := MonthCycleTab[Ord(p)];
end;
//@+node:sonam.20180324221400.1: *3* GetDividend
//@@c
function TPlanetCycle.GetDividend(p: Planet; accMoon: Int64): Int64;
begin
    result := accMoon mod MonthCycleTab[Ord(p)] * MonthCycleNum[Ord(p)] mod MonthCycleTab[Ord(p)];
end;
//@+node:sonam.20180324221450.1: *3* YearInCycle
//@+at
// 根據歷算論典book計算勝生y年p曜的三日共年之週年，即該年距離該曜
// 算餘為零的年之年數對三日共年取餘的週期內已經經過的年數
//@+node:sonam.20180324221537.1: *4* 函數頭
//@@c
function TPlanetCycle.YearInCycle(book: CalcBook; p: Planet; y: Integer) : Integer;
Const
//@+node:sonam.20180318214248.1: *4* 表一－三日共年
//@+at 所謂的三日共年，即是各曜從三种日的各各特定日期開始，又在該日回到
// 該數值所要經過的週期，單位是年。
// 由於每經過該週期，各曜的數值就重復出現一次，在歷算中，就爲每個曜
// 找到一個數值爲零的年初，從該年開始計算，這樣就不用考慮算餘的問題。
// 這就是后面多處要用到的以<三日共年週年>來推算的原理。
// 
//@@c
	YearCycle : TPlanetTab =
	  (643370, 65, 19110, 7475, 21047390,
	   132718040, 989503060, 808532270, 68840590);
//@+node:sonam.20180318214441.1: *4* 表六－各論典的三日共年之已過年數
//@+at 所謂三日共年之已過年數，是指丁卯西元1987年，距各曜算餘為零的年
// 已經經過的年數，對於不同的歷算論典，分別有不同的取值
// 
//@@c
	PastYearTab : TPlanetTabs =
	(
	  (109720, 0, 7800, 6825, 19594640, 92203540, 846784640, 382087680, 6543420),
	  (563200, 40, 2640, 1600, 12787230, 37143380, 941170140, 16187900, 41095510),
	  (66210, 40, 8880, 1600, 66210, 90229920, 448495100, 222947960, 47675590),
	  (592350, 5, 19050, 3385, 14930310, 8956160, 572548280, 265660790, 27613890),
	  (66210, 40, 8880, 1600, 66210, 90229920, 448495100, 374875190, 47675590),
	  (0,0,0,0,0,0,0,0,0)
	);
//@+node:sonam.20180324221707.1: *4* 函數實現
//@@c
var
	cycle: integer;
begin
	cycle := YearCycle[Ord(p)];
	Result := y - ManiBeginYear + PastYearTab[Ord(book)][Ord(p)];
	if Result >= cycle then
		Result := Result mod cycle
	else
		if Result < 0 then
			Result := Result mod cycle + cycle;
end;
//@+node:sonam.20180324221748.1: *3* ZodiacDayCycle
//@@c
function TPlanetCycle.ZodiacDayCycle(p: Planet) : Int64;
begin
    result := ZodiacDayCycleTab[Ord(p)];
end;
//@+node:sonam.20180324221815.1: *3* DayCycle
//@@c
function TPlanetCycle.DayCycle(p: Planet) : Int64;
begin
    result := DayCycleTab[Ord(p)];
end;
//@+node:sonam.20180324221841.1: *3* ETC
//@@c

function PlanetAccumMonth(y, month : Integer; LeapMonth: Boolean) : Int64;
Var
    dividend : Int64;
begin
    dividend := (Int64(y) * 12 + month) * 67;
    if ((dividend mod 65) <= 1) and not LeapMonth
         and (dividend div 65 <> 0) then
                result := (dividend div 65) - 1
    else
        result := dividend div 65;
end;
//@-others

end.
//@-leo
